package _general.problem;

import java.util.Comparator;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;

import _general.Config;
import _general.ObjectInterface;
import _general.TestInterface;
import _general.Window;
import _general.geometry.Edge;
import _general.geometry.EdgeList;
import _general.geometry.Node;
import _general.geometry.Point;
import _general.performanceTest.IllegalConfigException;

public abstract class CrossCount implements TestInterface {

	private String name = "";
	
	protected SortedSet<Point> pointSet = new TreeSet<Point>(new Comparator<Point>() {
		private final double eps = (double) 0.0000001;
		@Override
		public int compare(Point arg0, Point arg1) {
			if (Math.abs(arg0.getX() - arg1.getX()) < eps && Math.abs(arg1.getY() - arg0.getY()) < eps )
				return 0;
			else
				return (int) Math.signum(arg0.getX() - arg1.getX());
		}
		
	});
	
	protected EdgeList<Edge> activeEdge = new EdgeList<Edge>();
	protected int crossCount = 0;
	
	protected int rangeX, rangeY;
	
	public CrossCount() {
		try {
			this.getProblemRange();
		} catch (IllegalConfigException e) { e.printStackTrace(); }
	}
	
	public CrossCount(SortedSet<Point> pointSet, EdgeList<Edge> activeEdge) {
		this.pointSet = pointSet;
		this.activeEdge = activeEdge;
		
		try {
			this.getProblemRange();
		} catch (IllegalConfigException e) { e.printStackTrace(); }
	}
	
	@Override
	public boolean checkResult() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void createInitialList(String preSort, int numberElements)
			throws Exception {
		Edge nextEdge = null;
		Node startNode = null;
		Node endNode = null;
		
		startNode = new Node((float) 4.0, (float) 4.0);
		endNode = new Node((float) 14.0, (float) 9.0);
		nextEdge = new Edge(startNode, endNode);
		startNode.setEdge(nextEdge, true);
		endNode.setEdge(nextEdge, false);
		this.pointSet.add(nextEdge.getStart());
		this.pointSet.add(nextEdge.getEnd());
		
		startNode = new Node((float) 5.0, (float) 1.0);
		endNode = new Node((float) 17.0, (float) 3.75);
		nextEdge = new Edge(startNode, endNode);
		startNode.setEdge(nextEdge, true);
		endNode.setEdge(nextEdge, false);
		this.pointSet.add(nextEdge.getStart());
		this.pointSet.add(nextEdge.getEnd());
		
		startNode = new Node((float) 6.0, (float) 8.5);
		endNode = new Node((float) 9.0, (float) 2.5);
		nextEdge = new Edge(startNode, endNode);
		startNode.setEdge(nextEdge, true);
		endNode.setEdge(nextEdge, false);
		this.pointSet.add(nextEdge.getStart());
		this.pointSet.add(nextEdge.getEnd());
		
		startNode = new Node((float) 7.0, (float) 8.75);
		endNode = new Node((float) 16.0, (float) 3.0);
		nextEdge = new Edge(startNode, endNode);
		startNode.setEdge(nextEdge, true);
		endNode.setEdge(nextEdge, false);
		this.pointSet.add(nextEdge.getStart());
		this.pointSet.add(nextEdge.getEnd());
		
		startNode = new Node((float) 8.0, (float) 3.0);
		endNode = new Node((float) 11.0, (float) 4.5);
		nextEdge = new Edge(startNode, endNode);
		startNode.setEdge(nextEdge, true);
		endNode.setEdge(nextEdge, false);
		this.pointSet.add(nextEdge.getStart());
		this.pointSet.add(nextEdge.getEnd());
		
		startNode = new Node((float) 10.0, (float) 6.0);
		endNode = new Node((float) 15.0, (float) 2.0);
		nextEdge = new Edge(startNode, endNode);
		startNode.setEdge(nextEdge, true);
		endNode.setEdge(nextEdge, false);
		this.pointSet.add(nextEdge.getStart());
		this.pointSet.add(nextEdge.getEnd());

	}

	@Override
	public void createInitialList(String preSort, int size,
			long randomSeed) throws Exception {
		
		//createInitialList(preSort, size);

		int rangeX = this.rangeX;
		int rangeY = this.rangeY;
		
		Edge nextEdge = null;
		Node startNode = null;
		Node endNode = null;
		
		if (preSort.toLowerCase().equals("random")){
			Random ran = new Random(randomSeed);
			for (int i = 0; i < size; i++) {
				
				startNode = new Node((ran.nextDouble() * rangeX), (ran.nextDouble() * rangeY));
				endNode   = new Node((ran.nextDouble() * rangeX), (ran.nextDouble() * rangeY));
				
				
				if (startNode.getX() < endNode.getX()) {
					nextEdge = new Edge(startNode, endNode);
					startNode.setEdge(nextEdge, true);
					endNode.setEdge(nextEdge, false);
				} else {
					nextEdge = new Edge(endNode, startNode);
					startNode.setEdge(nextEdge, false);
					endNode.setEdge(nextEdge, true);
				}
				
				this.pointSet.add(nextEdge.getStart());
				this.pointSet.add(nextEdge.getEnd());
			}
		}
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

	@Override
	public Object get(int index) {
		return pointSet.toArray()[index];
	}

	
	public Object getResult() {
		return crossCount;
	}

	@Override
	public void problemToConsole() {
		
	}
	
	static Window<Point> Window;
	
	@Override
	public void problemToWindow() {
		//System.out.println("counted intersections: " + crossCount);
		
		Window = new Window<Point> (this.pointSet, "Cross Count Problem");
	}

	
	public void set(int index, ObjectInterface newElement) {
		
		// TODO Auto-generated method stub

	}
	
	@Override
	public void showResult() {
		System.out.println(this.getName() + ":\t counted intersections:\t" + crossCount);
		
	}

	@Override
	public void start() {
		// TODO Auto-generated method stub

	}

	////////////////////////////////////////////////////////////////
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	private void getProblemRange() throws IllegalConfigException {
		if (Config.problemRange.length < 2)
			throw new IllegalConfigException();
		this.rangeX = Config.problemRange[0];
		this.rangeY = Config.problemRange[1];
	}
}
